﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ClipBoard.h"
#include "IDocument.h"
#include "LevelUtils.h"
#include "ICopyOperator.h"
#include "IRegenerator.h"
#include "ICategoryLibrary.h"
#include "IElementRelationships.h"
#include "IFamily.h"
#include "FamilyUtils.h"
#include "IGenericType.h"
#include "IInstanceType.h"
#include "IElementModelShape.h"
#include "IReferencePlane.h"
#include "IModelView.h"
#include "IPasteHelper.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IDrawingLine.h"
#include "IDimension.h"
#include "IGenericElement.h"
#include "IAnnotationText.h"
#include "IEditMode.h"
#include "IEditModeBehavior.h"
#include "IEditModeCopyPasteComponent.h"
#include "Vector3dUtils.h"
#include "IGraphicsZoomFree.h"
#include "IPositionAssociatedPlane.h"
#include "IPositionTwoAssociatedPlanes.h"
#include "IDocumentManager.h"
#include "IDocumentEventArgs.h"
#include "IDocumentEvent.h"
#include "IElementTransformationComponent.h"
#include "IElementConstraintBehavior.h"
#include "GbmpModelViewUtil.h"
#include "ICopyContext.h"
#include "IFamilyConfigElement.h"
#include "IParameterDefinitionLibrary.h"
#include "DebugMode.h"
#include "IFamilyType.h"
#include "ICopyStrategyReporter.h"
#include "IInstance.h"
#include "IElement.h"
#include "IElementPosition.h"
#include "IPasteContext.h"
#include "IElementBasicInformation.h"
#include "ContainerUtil.h"
#include "IParameterDefinition.h"
#include "IGraphicsElementShape.h"
#include "IParameter.h"
#include "IElementParameters.h"
#include "GraphicsNodeUtils.h"
#include "IElementStatus.h"
#include "GbmpDocUtils.h"
#include "GbmpClonedElementPostProcessor.h"
#include "ClipBoardElementChangeHandler.h"
#include "ClipBoardUtils.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace std;

EXPOSE_DEBUG_MODE_EXPORT(DontCheckCopyElementIdReport, GBMP_MODEL_EXPORT);

CREATE_DEBUG_MODE(CopyAndChangeModelViewId, L"Ctrl+C支持跨视图复制", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"Ctrl+C支持跨视图复制。");

namespace
{
    // 注意!!!
    // 这个方法【只能】给IElementRelationships没有规范const使用方法的情况
    template<typename T>
    T* Const_Cast_For_ElementRelationships_Only(const T* t)
    {
        static_assert(std::is_base_of<IElementRelationships, T>::value, "Const cast is not allowed!");
        return const_cast<T*>(t);
    }

    //调整拷贝队列：把洞口和连接等依赖于其他构件的特殊对象按依赖关系排序
    bool PrepareCloneOrder(const IDocument* pDocFrom, vector<ElementId>& willBeCopiedElementIds)
    {
        vector<ElementId> commonElementIds;         //一般构件，不依赖其他元素，比如墙梁板柱
        vector<ElementId> holeElementIds;           //洞口构件，依赖主体
        vector<ElementId> relationShipElementIds;   //关系对象，比如开洞/连接等
        vector<ElementId> referencePlaneIds;           //关联平面

        ValueContainerUtil::RemoveRepeatItem(willBeCopiedElementIds);
        FOR_EACH(id, willBeCopiedElementIds)
        {
            const IElement* pElement = pDocFrom->GetElement(id);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");

            const IElementBasicInformation* pBasicInformation = pElement->GetBasicInformation();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pBasicInformation, L"pBasicInformation为空",L"GDMPLab",L"2024-03-30");

            const UniIdentity& uid = pBasicInformation->GetCategoryUid();
            if (uid == BuiltInCategoryUniIdentities::BICU_STRUCTURE_WALL_HOLE
                || uid == BuiltInCategoryUniIdentities::BICU_STRUCTURE_PLATE_HOLE)
            {
                holeElementIds.push_back(id);
            }
            else if (uid == BuiltInCategoryUniIdentities::BICU_ELEMENT_OPENING
                || uid == BuiltInCategoryUniIdentities::BICU_INSTANCE_JOIN)
            {
                relationShipElementIds.push_back(id);
            }
            else if (uid == BuiltInCategoryUniIdentities::BICU_REFERENCE_PLANE)
            {
                referencePlaneIds.push_back(id);
            }
            else
            {
                commonElementIds.push_back(id);
            }
        }

        willBeCopiedElementIds.clear();
        //参照平面排在最前面
        ValueContainerUtil::AddItems(willBeCopiedElementIds, referencePlaneIds);
        //普通的排在参照平面后面
        ValueContainerUtil::AddItems(willBeCopiedElementIds, commonElementIds);
        //然后是洞口之类的，因为他们会用到主体的id
        ValueContainerUtil::AddItems(willBeCopiedElementIds, holeElementIds);
        //然后是关系之类的，因为他们会用到主体及洞口的id
        ValueContainerUtil::AddItems(willBeCopiedElementIds, relationShipElementIds);

        return true;
    }
}

static std::vector<UniIdentity> GetFamilyParameterUids(const IDocument* pDoc, const IFamilyType* pFamilyType)
{
    DBG_WARN_AND_RETURN_UNLESS(pDoc && pFamilyType, std::vector<UniIdentity>(), L"函数的参数非法!",L"GDMPLab",L"2024-03-30");

    std::vector<UniIdentity> paramUids;
    const std::vector<OwnerPtr<IParameter>> famParams = pFamilyType->GetFamilyParameters();
    FOR_EACH(famParam, famParams)
    {
        paramUids.push_back(famParam->GetParameterDefinitionUid());
    }

    return paramUids;
}

static bool CheckIfTheSameFamily(
    const IDocument* pDocSrc, 
    const IFamily* pFamilySrc, 
    IDocument* pDocTarget, 
    const IFamily* pFamilyTarget)
{
    DBG_WARN_AND_RETURN_UNLESS(pDocSrc && pFamilySrc && pDocTarget && pFamilyTarget, false, L"函数的参数非法!",L"GDMPLab",L"2024-03-30");

    const UniIdentity& categoryUidSrc = pFamilySrc->GetBasicInformation()->GetCategoryUid();
    wstring familyNameSrc = pFamilySrc->GetBasicInformation()->GetName();

    const UniIdentity& categoryUidTarget = pFamilyTarget->GetBasicInformation()->GetCategoryUid();
    wstring familyNameTarget = pFamilyTarget->GetBasicInformation()->GetName();

    //---------------------------------------------------------------------
    //（1）属于相同类别(Category)
    if(categoryUidSrc != categoryUidTarget)
    {
        return false;
    }

    //---------------------------------------------------------------------
    // (2) 族名称相同
    if (familyNameSrc != familyNameTarget)
    {
        //因为引入了重命名族的规则，以下视作同名族(会作进一步比较参数)：
        //构件，构件（副本1）...构件（副本n）
        const wstring tag = GBMP_TR(L"（副本");
        wstring familyNameWithoutTagSrc = familyNameSrc;
        wstring familyNameWithoutTagTarget = familyNameTarget;

        auto tagPosSrc = familyNameSrc.find(tag);
        if ( tagPosSrc != wstring::npos )
        {
            familyNameWithoutTagSrc = familyNameSrc.substr(0, tagPosSrc);
        }

        auto tagPosTarget = familyNameTarget.find(tag);
        if ( tagPosTarget != wstring::npos )
        {
            familyNameWithoutTagTarget = familyNameTarget.substr(0, tagPosTarget);
        }

        if (familyNameWithoutTagSrc!=familyNameWithoutTagTarget)
        {
            return false;
        }
    }

    //---------------------------------------------------------------------
    // (3) 参数个数及类型相同
    auto& srcFamilyTypes = pFamilySrc->GetFamilyTypes();
    auto& targetFamilyTypes = pFamilyTarget->GetFamilyTypes();
    DBG_WARN_AND_RETURN_UNLESS(!srcFamilyTypes.empty() && !targetFamilyTypes.empty(), false, L"族下面应该至少有一个族类型！",L"GDMPLab",L"2024-03-30");

    const std::vector<UniIdentity>& srcFamilyParameterUids = GetFamilyParameterUids(pDocSrc,  quick_cast<IFamilyType>(srcFamilyTypes[0]));
    const std::vector<UniIdentity>& targetFamilyParameterUids = GetFamilyParameterUids(pDocTarget, quick_cast<IFamilyType>(targetFamilyTypes[0]));

    bool sameContent = ValueContainerUtil::IsSameContentContainer(srcFamilyParameterUids, targetFamilyParameterUids);
    if (!sameContent)
    {
        return false;
    }

    return true;
}

//当确定一个族需要从原文档拷贝至目标文档时，从目标文档中生成新的族名称
//(1）如果目标文档没有这个族名字，则使用原文档中的族名称
//(2）如果目标文档中已有这个族名字，则使用规则: 构件A, 构件A（副本1）...构件A（副本n）
static wstring GetNewFamilyName(const IDocument* pDocTo, const wstring& familyNameSrc)
{
    DBG_WARN_AND_RETURN_UNLESS(nullptr != pDocTo, L"", L"pDocTo为空！",L"GDMPLab",L"2024-03-30");
    std::vector<IFamily*> familyTargets = IFamily::GetAllFamilies(pDocTo);
    std::vector<wstring> familyTargetNames;
    FOR_EACH(familyTarget, familyTargets)
    {
        familyTargetNames.push_back(familyTarget->GetBasicInformation()->GetName());
    }

    if(ValueContainerUtil::IsInContainer(familyTargetNames, familyNameSrc))
    {
        //查找所有匹配族命名模式: 构件（副本n）
        const wstring prefix = familyNameSrc + GBMP_TR(L"（副本");
        const wstring posfix = GBMP_TR(L"）");

        //确定有重名族，这里主要计算出“副本”后的编号
        int newIndex = 1;  //副本编号默认从1开始
        FOR_EACH(familyTargetName, familyTargetNames)
        {
            auto prefixPos = familyTargetName.find(prefix);
            auto posfixPos = familyTargetName.find(posfix);
            //保证字符串是以[prefix]开头，并以[posfix]结尾
            if (prefixPos!=0 || familyTargetName.length()!=(posfixPos+posfix.length()))
            {
                //说明不匹配族命名模式: 构件（副本n）
                continue;
            }

            //取出中间的数字编号
            auto indexLen = familyTargetName.length() - prefix.length() - posfix.length();
            wstring number = familyTargetName.substr(prefix.length(), indexLen);
            //这个wstring=>int的转换函数不安全（有待改进）
            int index = StringUtil::ToNumber<int>(number);
            if (newIndex<=index)
            {
                newIndex = index+1;
            }
        }

        return prefix + StringUtil::ToWString(newIndex) + posfix;
    }
    else
    {
        return familyNameSrc;
    }
}

static ElementId GetOrCreateTargetFamily(const IDocument* pDocFrom, const IFamily* pFamilySrc, IDocument* pDocTo)
{
    //---------------------------------------------------------------------
    //【说明】是否是相同族的原则：
    // (1) 属于相同类别(Category)
    // (2) 族名称相同
    // (3) 参数个数及类型相同
    //---------------------------------------------------------------------
    DBG_WARN_AND_RETURN_UNLESS(pDocFrom && pFamilySrc && pDocTo, ElementId::InvalidID, L"输入的参数异常!",L"GDMPLab",L"2024-03-30");

    //查询匹配的族，目标文档进行Id绑定
    std::vector<IFamily*> familyTargets = IFamily::GetAllFamilies(pDocTo);
    FOR_EACH(familyTarget, familyTargets)
    {
        //族的类别/名称/参数个数及类型必需相同
        bool ret = CheckIfTheSameFamily(pDocFrom, pFamilySrc, pDocTo, familyTarget);
        if (!ret)
        {
            continue;
        }

        //仅仅有同名的族，但是族服务中并没有相应的配置
        //FamilyConfig.json及左侧面板族信息树中均无此族
        //目前建模业务中出现此种情况（可能是原来保存的文件内容状态已经不对了）
        wstring familyNameTarget = familyTarget->GetBasicInformation()->GetName();
        DBG_WARN_AND_CONTINUE_UNLESS(IFamilyConfigElement::GetFamilyConfigElementByName(pDocTo, familyNameTarget), L"【目标文档异常】：无法取得对应族的ConfigItem！族=>" + familyNameTarget ,L"GDMPLab",L"2024-03-30");

        return familyTarget->GetElementId();
    }

    //没有找到匹配的族，目标文档进行family复制
    wstring familyNameSrc = pFamilySrc->GetBasicInformation()->GetName();
    wstring familyNameNew = GetNewFamilyName(pDocTo, familyNameSrc);
    const IFamilyConfigElement* pFamilyConfigElementOld = IFamilyConfigElement::GetFamilyConfigElementByName(pDocFrom, familyNameSrc);
    DBG_WARN_AND_RETURN_UNLESS(pFamilyConfigElementOld, ElementId::InvalidID, L"FamilyConfigElement为空",L"GDMPLab",L"2024-03-30");

    const std::wstring familyPath = pFamilyConfigElementOld->GetFamilyFilePath(pDocFrom);

    IFamily* pFamilyNew = nullptr;
    ClipBoard* pClipBoard = dynamic_cast<ClipBoard*>(ClipBoard::Get());
    DBG_WARN_UNLESS(pClipBoard, L"获取默认的粘贴板管理器失败",L"GDMPLab",L"2024-03-30");
    if (LoadFamilyCallBackFunction loadFamilyCallBackFunction = pClipBoard->GetLoadFamilyCallBack())
    {
        pFamilyNew = quick_cast<IFamily>(loadFamilyCallBackFunction(pDocTo, familyPath));
        DBG_WARN_AND_RETURN_UNLESS(pFamilyNew, ElementId::InvalidID, L"获取Family异常!",L"GDMPLab",L"2024-03-30");
    }

    //根据情况重新调整族名称(因为原名称可能在目标文档会发生冲突)
    if (familyNameSrc != familyNameNew)
    {
        bool status = FamilyUtils::RenameFamily(pDocTo, familyNameSrc, familyNameNew);
        DBG_WARN_AND_RETURN_UNLESS(status, ElementId::InvalidID, L"族重命名失败!",L"GDMPLab",L"2024-03-30");
    }

    return pFamilyNew->GetElementId();
}

static ElementId GetOrCreateTargetType(const IDocument* pDocFrom, const IType* pTypeSrc, IDocument* pDocTo)
{
    //---------------------------------------------------------------------
    //【说明】是否是相同类型的原则：
    // (1) 属于相同类别(Category)
    // (2) 属于相同族（或者空族即系统类型）
    // (3) 相同的类型名称
    // (4) 相同的类型参数(这条可以PASS，因为相同族就会有相同的参数个数和类型)
    //---------------------------------------------------------------------

    const UniIdentity& categoryUidSrc = pTypeSrc->GetBasicInformation()->GetCategoryUid();

    const IFamily* pFamilySrc = nullptr;
    const IInstanceType* pInstanceTypeSrc = quick_cast<const IInstanceType>(pTypeSrc);
    if (pInstanceTypeSrc)
    {
        pFamilySrc = pInstanceTypeSrc->GetFamily();
    }

    wstring typeNameSrc = pTypeSrc->GetBasicInformation()->GetName();

    //---------------------------------------------------------------------
    //分成族类型和系统类型来处理会更有效率
    //1. 处理族类型
    if (pFamilySrc)
    {
        DBG_WARN_AND_RETURN_UNLESS(quick_cast<const IInstanceType>(pTypeSrc), ElementId::InvalidID,L"这个类型Type可以获取族却不是族类型!",L"GDMPLab",L"2024-03-30");

        //1.1 先生成或者找到对应Family (Category会在这一过程中被处理)
        ElementId familyIdTarget = GetOrCreateTargetFamily(pDocFrom, pFamilySrc, pDocTo);
        IElement* pElementTarget = pDocTo->GetElement(familyIdTarget);
        DBG_WARN_AND_RETURN_UNLESS(pElementTarget, ElementId::InvalidID, L"目标文档族状态异常!",L"GDMPLab",L"2024-03-30");
        IFamily* pFamilyTarget = quick_cast<IFamily>(pElementTarget);
        DBG_WARN_AND_RETURN_UNLESS(pFamilyTarget, ElementId::InvalidID, L"目标文档族状态异常!",L"GDMPLab",L"2024-03-30");

        //1.2 优先尝试找到对应FamilyType
        const std::vector<const IFamilyType*> familyTypeTargets = pFamilyTarget->GetFamilyTypes();
        bool foundType = false;
        FOR_EACH(familyTypeTarget, familyTypeTargets)
        {
            if (typeNameSrc == familyTypeTarget->GetName())
            {
                foundType = true;
                break;
            }
        }

        //1.3 没找到则添加对应FamilyType
        if (!foundType)
        {
            const IFamilyType* pFamilyTypeSrc = pFamilySrc->GetFamilyTypeByName(typeNameSrc);
            OwnerPtr<IFamilyType> pFamilyTypeTarget = IFamilyType::Create(typeNameSrc, pFamilyTypeSrc);
            pFamilyTarget->AddFamilyType(pFamilyTypeTarget.get());
        }

        //1.4 生成或者查询对应的InstanceType
        IInstanceType* pInstanceType = pFamilyTarget->GetInstanceTypeByName(typeNameSrc);
        if (pInstanceType == nullptr)
        {
            pInstanceType = pFamilyTarget->CreateInstanceType(typeNameSrc);
        }
        DBG_WARN_AND_RETURN_UNLESS(pInstanceType, ElementId::InvalidID, L"获取目标文档族类型异常!",L"GDMPLab",L"2024-03-30");

        // (1) 需要添加一个一键修复功能，比如删除游离族，给类型绑定好Category信息 (老模型中缺少这样的信息，尽早修复比较好)
        // (2) 族状态检测，生成一个详细列表（类别/族名称/类型 等相关信息）
        // (3) 这一个DBG_WARN先关闭（虹桥模型中的InstanceType对象，原来是不带有Category信息的）
        DBG_WARN_AND_RETURN_UNLESS(true || categoryUidSrc==pInstanceType->GetBasicInformation()->GetCategoryUid(), ElementId::InvalidID,L"同一个族下面的族类型，它的Category怎么会不相同!",L"GDMPLab",L"2024-03-30");

        return pInstanceType->GetElementId();
    }
    //2. 处理系统类型
    else
    {
        DBG_WARN_AND_RETURN_UNLESS(quick_cast<const IGenericType>(pTypeSrc), ElementId::InvalidID,L"这个类型Type不能获取族却不是系统类型!",L"GDMPLab",L"2024-03-30");

        //2.1 先去查找相同的系统类型：绑定
        std::vector<IElement*> systemTypeTargets = gcmp::GbmpDocUtils::GetElementsByCategory(pDocTo, BuiltInCategoryUniIdentities::BICU_NEW_LEVEL_TYPE);
        FOR_EACH(systemTypeTarget, systemTypeTargets)
        {
            const UniIdentity& categoryUidTarget = systemTypeTarget->GetBasicInformation()->GetCategoryUid();
            wstring typeNameTarget = systemTypeTarget->GetBasicInformation()->GetName();
            if(categoryUidSrc == categoryUidTarget && typeNameSrc == typeNameTarget)
            {
                return systemTypeTarget->GetElementId();
            }
        }

        //2.2 没有找到相同的系统类型：生成
        DBG_WARN_AND_RETURN_UNLESS(false, ElementId::InvalidID, L"如果出现这种业务，请先完善LevelType复制逻辑!",L"GDMPLab",L"2024-03-30");
    }

    return ElementId::InvalidID;
}

static ElementId GetRefPlaneIdForDrawingLine(const IDocument* pDocTo, ElementId modelViewId)
{
    IElement* pElement = pDocTo->GetElement(modelViewId);
    DBG_WARN_AND_RETURN_UNLESS(pElement, ElementId::InvalidID, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    IModelView* pModelView = quick_cast<IModelView>(pElement);
    DBG_WARN_AND_RETURN_UNLESS(pModelView, ElementId::InvalidID, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    //目前仅支持平面视图二维线的拷贝
    ElementId idRefPlaneForDrawingLine;
    if(Vector3dUtils::IsEqual(pModelView->GetViewDirection(), Vector3d::NegaUnitZ))
    {
        std::vector<IReferencePlane*> vecRefPlanes = IReferencePlane::GetAllReferencePlanes(pDocTo);
        FOR_EACH(pRefPlane, vecRefPlanes)
        {
            if (pRefPlane->GetProjectReferenceType() == ProjectReferenceTypeOfReferencePlane::CenterOfTopBottom)
            {
                idRefPlaneForDrawingLine = pRefPlane->GetBasicInformation()->GetElementId();
                const IPlane* gPlanePtr = pRefPlane->GetGeometryPlane();
                if(!gPlanePtr)
                {
                    continue;
                }
                break;
            }
        }
    }

    return idRefPlaneForDrawingLine;
}

//粘贴合法性检测：
//(1) 编辑模式内、编辑模式外相互之间不允许粘贴、不通编辑模式之间不允许粘贴
//(2) 如果Copy对象为Instance，但它的Host不在来源集合中，则粘贴失败
//(3) 如果Copy对象为Instance，且它的的族名称在目标文档已经存在但类别却不同，则粘贴失败

static bool ValidateCopyElements(
    IDocument* pDocFrom, 
    const std::vector<ElementId>& sourceEleIds, 
    bool isEditMode, 
    std::wstring editModeType, 
    const IDocument* pDocTo)
{
    //(1) 编辑模式内、编辑模式外相互之间不允许粘贴、不通编辑模式之间不允许粘贴
    {
        IEditMode* pTopActiveEditMode = IEditMode::GetTopActiveEditMode(pDocTo);
        bool curIsEditMode = (pTopActiveEditMode!=nullptr);
        if(!curIsEditMode == isEditMode)
        {
            if (curIsEditMode)
            {
                ClipBoard::Get()->SetErrorMessage(GBMP_TR(L"编辑模式外的内容不允许复制到编辑模式内"));
            }
            else
            {
                ClipBoard::Get()->SetErrorMessage(GBMP_TR(L"编辑模式内的内容不允许复制到编辑模式外"));
            }

            return false;
        }
        else if(curIsEditMode)
        {
            if (editModeType != pTopActiveEditMode->GetEditModeType())
            {
                ClipBoard::Get()->SetErrorMessage(GBMP_TR(L"不同编辑模式之间暂不支持复制"));

                return false;
            }
        }
    }

    FOR_EACH(sourceEleId, sourceEleIds)
    {
        IElement* pElement = pDocFrom->GetElement(sourceEleId);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        const IInstance* pInstance = quick_cast<IInstance>(pElement);
        if(pInstance == nullptr)
        {
            continue;
        }

        //(2) 如果Copy对象为Instance，但它的Host不在来源集合中，则粘贴失败
        {
            ElementId hostId = pInstance->GetHostInstanceId();
            if (hostId.IsValid() && !ValueContainerUtil::IsInContainer(sourceEleIds, hostId))
            {
                IElement* pHost = pDocFrom->GetElement(hostId);
                DBG_WARN_AND_RETURN_UNLESS(pHost, false, L"找不到Host对象！",L"GDMPLab",L"2024-03-30");

                wstring instanceFamilyName;
                IFamily* pInstanceFamily = pInstance->GetFamily();
                if(pInstanceFamily)
                {
                    instanceFamilyName = pInstanceFamily->GetBasicInformation()->GetName();
                }

                wstring instanceTypeName;
                IType* pInstanceType = pInstance->GetBasicInformation()->GetType();
                if(pInstanceType)
                {
                    instanceTypeName = pInstanceType->GetBasicInformation()->GetName();
                }

                const IInstance* pHostInstance = quick_cast<const IInstance>(pHost);
                DBG_WARN_AND_RETURN_UNLESS(pHostInstance, false, L"pHost不是实例",L"GDMPLab",L"2024-03-30");
                IFamily* pHostFamily = pHostInstance->GetFamily();

                wstring hostFamilyName;
                if(pHostFamily)
                {
                    hostFamilyName = pHostFamily->GetBasicInformation()->GetName();
                }

                IType* pHostType = pHost->GetBasicInformation()->GetType();
                wstring hostTypeName;
                if(pHostType)
                {
                    hostTypeName = pHostType->GetBasicInformation()->GetName();
                }

                wstring instanceInfo = instanceFamilyName + L","
                    + instanceTypeName + L"," 
                    + pInstance->GetBasicInformation()->GetName() + L"-ID" + std::to_wstring(pInstance->GetElementId().AsInt64());

                wstring hostInfo = hostFamilyName + L"," 
                    + hostTypeName + L"," 
                    + pHost->GetBasicInformation()->GetName() + L"-ID" +  std::to_wstring(pHost->GetElementId().AsInt64());

                ClipBoard::Get()->SetErrorMessage(GBMP_TR(L"构件【") + instanceInfo + GBMP_TR(L"】被拷贝，但是它的Host构件【") + hostInfo + GBMP_TR(L"】未被拷贝！"));

                return false;
            }
        }

        //(3) 如果Copy对象为Instance，且它的的族名称在目标文档已经存在但类别却不同，则粘贴失败
        {
            if(IFamily* pFamilySrc = pInstance->GetFamily())
            {
                std::vector<IFamily*> familyTargets = IFamily::GetAllFamilies(pDocTo);
                FOR_EACH(familyTarget, familyTargets)
                {
                    const UniIdentity& categoryUidSrc = pFamilySrc->GetBasicInformation()->GetCategoryUid();
                    wstring familyNameSrc = pFamilySrc->GetBasicInformation()->GetName();

                    const UniIdentity& categoryUidTarget = familyTarget->GetBasicInformation()->GetCategoryUid();
                    wstring familyNameTarget = familyTarget->GetBasicInformation()->GetName();

                    if (familyNameSrc==familyNameTarget && categoryUidSrc!=categoryUidTarget)
                    {
                        ClipBoard::Get()->SetErrorMessage(GBMP_TR(L"【族复制异常】：族名字相同，但是类别CategoryUid不同(这可能会导致未来不可预料的错误，请先修改)! 族名称 =>") + familyNameSrc);
                        return false;
                    }
                }
            }
        }
    }

    return true;
}

//复制于PositionHelper逻辑
static bool CopyElementsByPositionBehavior(
    IElement* pCopiedElement, 
    IDocument* pDocFrom, 
    IDocument* pDocTo, 
    const ElementId& id, 
    std::unordered_map<ElementId, ElementId, ElementIdHash>& newToOldIdTable, 
    const Vector3d& offset)
{
    IElementPosition* positionBehaviorFW = pCopiedElement->GetElementPosition();
    if (positionBehaviorFW == nullptr)
    {
        return false;
    }

    const IElementPosition* positionBehaviorOld = nullptr;   //未来会持续改进，先满足当前功能
    if (pDocFrom == pDocTo)
    {
        //同文档复制，楼层绑定信息依然被复制到新的Element中来了
        positionBehaviorOld = positionBehaviorFW;
    }
    else
    {
        const IElement* pOldElement = pDocFrom->GetElement(newToOldIdTable[id]);
        DBG_WARN_AND_RETURN_UNLESS(pOldElement, false, L"复原来的对象有空值！",L"GDMPLab",L"2024-03-30");

        //跨文档复制，楼层绑定信息已丢失(强关联楼层被过滤，弱关联楼层自动丢失)
        positionBehaviorOld = pOldElement->GetElementPosition();
    }


    ElementId baseId;
    ElementId topId;
    double baseOffset = 0.0;
    double endPosOffset = 0.0;
    double topOffset = 0.0;

    //---------------------------------------------------------------------
    //调整计算底部关联楼层及偏移
    const IPositionAssociatedPlane* pAssociatedPlaneOld 
        = (positionBehaviorOld ? positionBehaviorOld->GetPositionAssociatedPlane() : nullptr);
    if (pAssociatedPlaneOld != nullptr )
    {
        ElementId baseElementId = pAssociatedPlaneOld->GetBasePlaneElementId();
        if (baseElementId != ElementId::InvalidID)
        {
            //构件更新后理论关联楼层标高值
            double elevation = pAssociatedPlaneOld->GetBasePlaneHeight() + offset.Z();

            //构件更新后的实际关联标高楼层
            ElementId newLevelId = ClipBoardUtils::FindNearestLevelByHeight(pDocTo, elevation);
            double newElevation = ClipBoardUtils::GetLevelElevation(pDocTo, newLevelId);

            //构件更新后的底部实际偏移
            double baseOffset = 0.0;
            baseOffset = pAssociatedPlaneOld->GetBasePlaneOffset();
            double baseElevation = elevation + baseOffset;    //计算底部标高值

            baseId = newLevelId;
            baseOffset = baseElevation - newElevation;

            IPositionAssociatedPlane*  planePosition = positionBehaviorFW->GetPositionAssociatedPlane();
            if (planePosition != nullptr)
            {
                planePosition->SetBasePlaneElementId(baseId);
                planePosition->SetBasePlaneOffset(baseOffset);
            }

            IPositionTwoAssociatedPlanes* pTwoAssociatedPlanes = quick_cast<IPositionTwoAssociatedPlanes>(planePosition);
            if (pTwoAssociatedPlanes != nullptr)
            {
                double endPosElevation = elevation + pTwoAssociatedPlanes->GetTopOffset();
                endPosOffset = endPosElevation - newElevation;
                pTwoAssociatedPlanes->SetTopOffset(endPosOffset);
            }
        }
        else
        {
            positionBehaviorFW->Translate(offset);
        }
    }

    //---------------------------------------------------------------------
    //调整计算顶部关联楼层及偏移
    const IPositionTwoAssociatedPlanes *pTwoAssociatedPlanesOld 
        = quick_cast<const IPositionTwoAssociatedPlanes>(positionBehaviorOld->GetPositionAssociatedPlane());
    if (pTwoAssociatedPlanesOld != nullptr)
    {
        ElementId topElementId = pTwoAssociatedPlanesOld->GetTopAssociatedPlaneId();
        if (topElementId != ElementId::InvalidID)
        {
            //构件更新后理论关联标高值
            double elevation = pTwoAssociatedPlanesOld->GetTopAssociatedPlaneHeight() + offset.Z();

            //构件更新后的实际关联标高楼层
            ElementId newLevelId = ClipBoardUtils::FindNearestLevelByHeight(pDocTo, elevation);
            double newElevation = ClipBoardUtils::GetLevelElevation(pDocTo, newLevelId);

            //构件更新后的顶部实际偏移
            double topElevation = elevation + pTwoAssociatedPlanesOld->GetTopOffset();   //计算顶部标高值

            topId = newLevelId;
            topOffset = topElevation - newElevation;

            IPositionTwoAssociatedPlanes *pTwoAssociatedPlanes 
                = quick_cast<IPositionTwoAssociatedPlanes>(positionBehaviorFW->GetPositionAssociatedPlane());
            if (pTwoAssociatedPlanes != nullptr)
            {
                pTwoAssociatedPlanes->SetTopAssociatedPlaneId(topId);
                pTwoAssociatedPlanes->SetTopOffset(topOffset);
            }
        }
    }

    return true;
}

//从CopyOperator中解耦移出来的，后续重构代码时，会去除掉
namespace gcmp
{
    class CopyElementsImpl
    {
    public:
        std::vector<ElementId> CopyElements(
            const IDocument* pDocFrom, 
            IDocument* pIDocTo, 
            ElementId modelViewId, 
            const std::vector<ElementId>& sourceElementIds, 
            unordered_map<ElementId, ElementId, ElementIdHash>& newToOldIdMap, 
            const std::map<ElementId, ElementId>& sourceToTargetIds);

    private:
        void ReplaceParameters(const IDocument* pDocFrom, IDocument* pDocTo, IElement* pElem);
    };
}

std::vector<ElementId> CopyElementsImpl::CopyElements(
    const IDocument* pDocFrom, 
    IDocument* pIDocTo, 
    ElementId modelViewId, 
    const std::vector<ElementId>& sourceElementIds, 
    unordered_map<ElementId, ElementId, ElementIdHash>& newToOldIdMap, 
    const std::map<ElementId, ElementId>& sourceToTargetIds)
{
    //////////////////////////////////////////////////////////////////////////
    //说明：
    //将原文档对象，及其相关的强PARENTS全部拷贝一份至目标文档，并调整关联属性
    //强PARENTS只能是系统里的特定类型或者本身位于选择集合中，若不是则拷贝失败
    //(即单独拷贝一个窗是会报错的，后续会补充检测)
    //////////////////////////////////////////////////////////////////////////

    //即将被拷贝的源文档ElementId:
    //(1)输入的原文档ElementId集合
    //(2)上述集合的间接或直接强依赖的所有ElementId
    set<ElementId> allIdsToCopy;

    //即将放弃的源文档ElementId:
    //(1) 上述集合对应对象的弱关联ID
    //(2）会优先去上述集合中查找，找不到的则放弃
    set<ElementId> allIdsMayDiscard;

    set<ElementId> allIdsToAsk;

    //////////////////////////////////////////////////////////////////////////
    //STEP1. 访问所有即将被拷贝的源文档ElementId 
    //(每一轮访问一个节点，并将其加入allIdsToCopy)
    set<ElementId> visitingIds(sourceElementIds.begin(), sourceElementIds.end());

    //用于记录需要特殊处理的二维线的Id
    set<ElementId> drawingLineIds;
    //用于记录需要特殊处理的尺寸标注的Id
    set<ElementId> dimensionIds;
    //用于记录需要特殊处理的文字的Id
    set<ElementId> annotationTextIds;

    IDocument* pDocTo = quick_cast<IDocument>(pIDocTo);
    while(!visitingIds.empty())
    {
        //这些本轮即将访问的都是即将拷贝的Element
        allIdsToCopy.insert(visitingIds.begin(), visitingIds.end());

        //用来存放下轮遍历的Element(都是本轮访问集合的强Parents)
        set<ElementId> visitNextRound;
        FOR_EACH(id, visitingIds)
        {
            const IElement* pElem = pDocFrom->GetElement(id);
            DBG_WARN_AND_RETURN_UNLESS(pElem, std::vector<ElementId>(), L"invalid parameter",L"GDMPLab",L"2024-03-30");

            //关联更新
            IDocument* pElemDoc = pElem->GetDocument();
            DBG_WARN_AND_RETURN_UNLESS(pElemDoc , std::vector<ElementId>(), L"invalid parameter",L"GDMPLab",L"2024-03-30");
            IRegenerator* pRegen = pElemDoc->GetRegenerator();
            DBG_WARN_AND_RETURN_UNLESS(pRegen , std::vector<ElementId>(), L"invalid parameter",L"GDMPLab",L"2024-03-30");
            pRegen->RegenerateElement(pElem->GetElementId());

            //获得关联Parents
            const IElementRelationships* pReporter = IElementRelationships::GetElementRelationships(pDocFrom);
            auto& strongParentIds = Const_Cast_For_ElementRelationships_Only(pReporter)->GetStrongParents(pElem->GetElementId());
            auto& weakParentIds = Const_Cast_For_ElementRelationships_Only(pReporter)->GetWeakParents(pElem->GetElementId());

            OwnerPtr<ICopyContext> opCopyContext 
                = ICopyContext::Create(std::unordered_set<ElementId, ElementIdHash>(allIdsToCopy.begin(), allIdsToCopy.end()));
            OwnerPtr<ICopyStrategyReporter> opCopyStrategyReporter = ICopyStrategyReporter::Create();
            const IElementCopyStrategyComponent * pIElementCopyStrategyComponent = pElem->GetElementCopyStrategyComponent();
            GBMP_ASSERT(pIElementCopyStrategyComponent != nullptr);
            pIElementCopyStrategyComponent->Report(*opCopyContext, *opCopyStrategyReporter);

            //将所有的强Parents和toCopy加入到即将访问的集合中(自动去重)
            //此处对二维线、尺寸标注、文字做特殊处理
            const IElementCopyPasteComponent * pCopyPasteComponent = pElem->GetCopyPasteComponent();
            GBMP_ASSERT(pCopyPasteComponent && L"pCopyPasteComponent == nullptr?");
            if(pCopyPasteComponent && pCopyPasteComponent->IsStrongParentsNeedCopied())
            {
                visitNextRound.insert(strongParentIds.begin(), strongParentIds.end());
            }
            else if(const IDrawingLine* pDrawingLine = quick_cast<const IDrawingLine>(pElem))
            {
                drawingLineIds.insert(id);
            }
            else if(const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(pElem))
            {
                const IDimension* pDimension = quick_cast<const IDimension>(pGenericElement->GetExternalObject());
                if (pDimension)// 如果是尺寸标注
                {
                    dimensionIds.insert(id);
                }
            }
            else if(const IAnnotationText* pAnnotationText = quick_cast<const IAnnotationText>(pElem))
            {
                annotationTextIds.insert(id);
            }

            visitNextRound.insert(opCopyStrategyReporter->GetIdsToCopy().begin(), opCopyStrategyReporter->GetIdsToCopy().end());
            
            //草图线的StrongParents不应该被拷贝
            FOR_EACH(sourceToTargetId, sourceToTargetIds)
            {
                visitNextRound.erase(sourceToTargetId.first);
            }

            //将所有的弱Parents加入到即将【可能】放弃的集合中(自动去重)
            allIdsMayDiscard.insert(weakParentIds.begin(), weakParentIds.end());
        }

        //过滤visitNextRound中已经被访问过的节点(即allIdsToCopy中的节点)
        set<ElementId> notVisited;
        set_difference(visitNextRound.begin(), visitNextRound.end(), allIdsToCopy.begin(), allIdsToCopy.end(), std::inserter(notVisited, notVisited.end()));
        std::swap(visitingIds, notVisited);
    }

    std::set<ElementId> toCopy_ToBeDeleted;
    OwnerPtr<ICopyContext> opCopyContext 
        = ICopyContext::Create(std::unordered_set<ElementId, ElementIdHash>(allIdsToCopy.begin(), allIdsToCopy.end()));
    
    FOR_EACH(idToCopy, allIdsToCopy)
    {
        const IElement* pToAskElem = pDocFrom->GetElement(idToCopy);
        DBG_WARN_AND_RETURN_UNLESS(pToAskElem != nullptr, std::vector<ElementId>(), L"invalid parameter",L"GDMPLab",L"2024-03-30");

        bool shouldBeCopiedTogether = false;
        if (pToAskElem)
        {
            const IElementCopyPasteComponent * pICopyPasteComponent = pToAskElem->GetCopyPasteComponent();
            GBMP_ASSERT(pICopyPasteComponent != nullptr);
            shouldBeCopiedTogether = pICopyPasteComponent->ShouldBeCopiedTogether(*opCopyContext);
        }

        if (!shouldBeCopiedTogether)
        {
            toCopy_ToBeDeleted.insert(idToCopy);
        }
    }
    
    FOR_EACH(toBeDeleted, toCopy_ToBeDeleted)
    {
        allIdsToCopy.erase(toBeDeleted);
    }

    //////////////////////////////////////////////////////////////////////////
    //STEP2.将allIdsToCopy拷贝去目标文档，并建立源文档至目标文档的ID对照表
    std::unordered_map<ElementId, ElementId, ElementIdHash> oldToNewIdTable(allIdsToCopy.size()*2);

    //从即将【可能】放弃的Id中去除确定要拷贝的
    set<ElementId> idsToDiscard;
    set_difference(
        allIdsMayDiscard.begin(),
        allIdsMayDiscard.end(),
        allIdsToCopy.begin(),
        allIdsToCopy.end(),
        std::inserter(idsToDiscard, idsToDiscard.end()));

    //放弃的id引用，在目标文档中为invalid (除非目标文档生成了对应的就会更新对照表)
    FOR_EACH(id, idsToDiscard)
    {
        oldToNewIdTable.insert(make_pair(id, ElementId::InvalidID));
    }
 
    //目标文档生成新的对象，并更新ID对照表
    std::vector<std::pair<const IElement*,IElement*>> oldToNewElements;
    oldToNewElements.reserve(allIdsToCopy.size());

    //真正被拷贝到目标文档的对象
    std::vector<ElementId> copiedTargetElemIds;

    //需要重新生成的对象集合(一个实例的拷贝可能导致要同时拷贝它的类型/族/类别等)
    std::vector<ElementId> elementsWillBeCopied;
    FOR_EACH(id, allIdsToCopy)
    {
        //原始对象
        const IElement* pSrcElem = pDocFrom->GetElement(id);
        const UniIdentity& categoryUidFrom = pSrcElem->GetBasicInformation()->GetCategoryUid();

        //////////////////////////////////////////////////////////////////////////
        //以下全部为临时方案，保证功能完整性(未来会考虑更好的策略):
        //特殊处理一些不应该被拷贝过来的对象(或者需要合并至新文档)
        //////////////////////////////////////////////////////////////////////////
        {
            //------------------------------------------------------------------------
            //1. 过滤标高
            if (categoryUidFrom == BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION)
            {
                //标高因为会被重新绑定（这里放弃）
                continue;
            }

            //------------------------------------------------------------------------
            //2. 过滤剖面(暂时过滤)
            if (categoryUidFrom == BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL
                || categoryUidFrom == BuiltInCategoryUniIdentities::BICU_VIEW_SYMBOL_AUXILIARY_BORDER
                || categoryUidFrom == BuiltInCategoryUniIdentities::BICU_SECTION_VIEW_SYMBOL
                || categoryUidFrom == BuiltInCategoryUniIdentities::BICU_SECTION_VIEW_SYMBOL_LINE)
            {
                continue;
            }

            //------------------------------------------------------------------------
            //3. 过滤族/类型（会在拷贝实例时被处理，目前它们不可能被单独拷贝）
            if (quick_cast<const IFamily>(pSrcElem) || quick_cast<const IType>(pSrcElem))
            {
                continue;
            }

            //------------------------------------------------------------------------
            //4. 实例处理
            //4.1 实例的类别处理
            if (categoryUidFrom.IsValid())
            {
                bool foundCategory = false;
                if (ICategoryLibrary::Get(pDocTo)->GetCategory(categoryUidFrom))
                {
                    foundCategory = true;
                }
                DBG_WARN_AND_CONTINUE_UNLESS(foundCategory, L"目标文档没有此类别(请重新设计类别复制逻辑)！",L"GDMPLab",L"2024-03-30");
            }

            //4.2 实例的族处理
            const IInstance* pSrcInstance = quick_cast<const IInstance>(pSrcElem); 
            if(pSrcInstance)
            {
                const IFamily* pFamilySrc = quick_cast<IFamily>(pSrcInstance->GetFamily());
                if(pFamilySrc)
                {
                    ElementId familyIdTarget = GetOrCreateTargetFamily(pDocFrom, pFamilySrc, pDocTo);
                    DBG_WARN_AND_RETURN_UNLESS(familyIdTarget.IsValid(), std::vector<ElementId>(), L"族复制发生异常！",L"GDMPLab",L"2024-03-30");
                    oldToNewIdTable[pFamilySrc->GetElementId()] = familyIdTarget;
                }
            }

            //4.3 实例的类型处理
            const IType* pTypeSrc = pSrcElem->GetBasicInformation()->GetType();
            if (pTypeSrc)
            {
                ElementId targetTypeId = GetOrCreateTargetType(pDocFrom, pTypeSrc, pDocTo);
                DBG_WARN_AND_RETURN_UNLESS(targetTypeId.IsValid(), std::vector<ElementId>(), L"类型复制发生异常！",L"GDMPLab",L"2024-03-30");
                oldToNewIdTable[pTypeSrc->GetElementId()] = targetTypeId;
            }

            //4.4 实例处理(实例本身肯定需要拷贝的)
            elementsWillBeCopied.push_back(id);
        }
    }

    FOR_EACH(sourceToTargetId, sourceToTargetIds)
    {
        oldToNewIdTable.insert(sourceToTargetId);
    }
 
    //此处对二维线做特殊处理
    ElementId idRefPlaneForDrawingLine = GetRefPlaneIdForDrawingLine(pDocTo, modelViewId);
    FOR_EACH(drawingLineId, drawingLineIds)
    {
        IElement* pElement = pDocTo->GetElement(oldToNewIdTable[drawingLineId]);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        IDrawingLine* pDrawingLine = quick_cast<IDrawingLine>(pElement);
        DBG_WARN_AND_CONTINUE_UNLESS(pDrawingLine, L"pDrawingLine为空",L"GDMPLab",L"2024-03-30");
        oldToNewIdTable.insert(pair<ElementId, ElementId>(IElementPosition::GetAssociatedPlaneId(pDrawingLine), idRefPlaneForDrawingLine));
    }

    //////////////////////////////////////////////////////////////////////////
    //调整拷贝队列：把洞口和连接等依赖于其他构件的特殊对象最后复制
    PrepareCloneOrder(pDocFrom, elementsWillBeCopied);

    //////////////////////////////////////////////////////////////////////////
    //执行真正的拷贝，族相关的对象前面遍历已经生成，这些延迟生成可以防止族依赖；
    //全部拷贝完后对象自身及关联关系状态已调整到位，比如连接/开洞等
    FOR_EACH(elementId, elementsWillBeCopied)
    {
        const IElement* pSrcElement = pDocFrom->GetElement(elementId);
        GbmpClonedElementPostProcessor postProcessor;
        IElement* pNewElem = nullptr;
        ElementId newElementId = pDocTo->Clone(pSrcElement, &oldToNewIdTable, &postProcessor, pNewElem);
        oldToNewIdTable[elementId] = newElementId;
        copiedTargetElemIds.push_back(newElementId);
        oldToNewElements.push_back(make_pair(pSrcElement, pNewElem));

        // 替换参数信息(原文档的参数在目标文档中可能还没有添加)
        ReplaceParameters(pDocFrom, pDocTo, pNewElem);

        // 新文档中相关非法约束Id号需要清除
        if (IElementConstraintBehavior* pElementConstraintBehavior = pNewElem->GetElementConstraintBehaviorFW())
        {
            pElementConstraintBehavior->ClearFamilyConstraintIds();
        }        
    }

    // 此处对尺寸标注做特殊处理
    FOR_EACH(dimensionId, dimensionIds)
    {
        IElement* pElement = pDocTo->GetElement(oldToNewIdTable[dimensionId]);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElement);
        if(pGenericElement)
        {
            IDimension* pDimension = quick_cast<IDimension>(pGenericElement->GetExternalObject());
            if(pGenericElement)
            {
                pDimension->SetViewId(modelViewId);
            }
        }
    }

    // 此处对文字做特殊处理
    FOR_EACH(annotationTextId, annotationTextIds)
    {
        IElement* pElement = pDocTo->GetElement(oldToNewIdTable[annotationTextId]);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        IAnnotationText* pAnnotation = quick_cast<IAnnotationText>(pElement);
        if(pAnnotation)
        {
            pAnnotation->SetModelViewId(modelViewId);
        }
    }

    std::set<ElementId> elementsWillBeCopiedSet;
    FOR_EACH(elementId, elementsWillBeCopied) 
    {
        elementsWillBeCopiedSet.insert(elementId);
    }

    const ICopyOperator* pBuiltInCopyOperator = ICopyOperator::Get();
    DBG_WARN_UNLESS(pBuiltInCopyOperator != nullptr, L"默认的拷贝器不应该为空",L"GDMPLab",L"2024-03-30");
    // TODOTODO 该接口是否合适
    pBuiltInCopyOperator->AskElementsToUpdateForWeakParentCopied(
        pDocFrom, 
        pDocTo, 
        oldToNewElements, 
        elementsWillBeCopiedSet, 
        sourceToTargetIds);

    //将Map的OLD与NEW对换一下，复制出去供外部使用（后续会继续改进）
    for (auto iter = oldToNewIdTable.begin(); iter != oldToNewIdTable.end(); ++iter)
    {
        newToOldIdMap.insert(make_pair(iter->second, iter->first));
    }

    return copiedTargetElemIds;
}


//形参pElem中的参数信息还是原文档的绑定，需要调整至新文档绑定（这一过程中可能会修改目标文档的全局参数管理信息）
void gcmp::CopyElementsImpl::ReplaceParameters(const IDocument* pDocFrom, IDocument* pDocTo, IElement* pElem)
{
    auto& paramMap = pElem->GetElementParameters()->GetEmbeddedParametersMapFw();
    std::map<Int32, OwnerPtr<IParameter>> newParamsMap;
    for(auto it = paramMap.begin(); it != paramMap.end(); ++it)
    {
        //原文档：获取全局唯一标识
        const IParameterDefinitionLibrary* parameterDefinitionLibraryFrom = IParameterDefinitionLibrary::Get(pDocFrom);
        UniIdentity paramDefUid = parameterDefinitionLibraryFrom->GetParameterDefinitionUidById(it->first);

        //新文档：通过全局唯一标识来查询
        IParameterDefinitionLibrary* parameterDefinitionLibraryTo = IParameterDefinitionLibrary::Get(pDocTo);
        const IParameterDefinition* pdTo = parameterDefinitionLibraryTo->GetParameterDefinitionByUid(paramDefUid);

        //新文档有这样的参数定义: 获得它在目标文档的id，并绑定
        //新文档没有这样的参数定义: 先添加，同上
        if(nullptr == pdTo)
        {
            const IParameterDefinition* pdFrom = parameterDefinitionLibraryFrom->GetParameterDefinitionByUid(paramDefUid);

            OwnerPtr<IParameterDefinition> opdFrom = IParameterDefinition::CreateParameterDefinition(
                pdFrom->GetUid(),
                pdFrom->GetName(),
                pdFrom->GetGroupName(),
                pdFrom->GetDescription(),
                pdFrom->GetStorageType(),
                pdFrom->GetUnitType(),
                pdFrom->GetDisplayType());

            parameterDefinitionLibraryTo->AddParameterDefinition(TransferOwnership(opdFrom));
        }

        int newParamDefId = parameterDefinitionLibraryTo->GetParameterDefinitionIdByUid(paramDefUid);
        const IParameter* pParameterData = (it->second).get();
        //OwnerPtr<IParameter> opNewParameter = NEW_AS_OWNER_PTR(Parameter, pDocTo, pParameterData);
        OwnerPtr<IParameter> opNewParameter = pParameterData->Clone();
        opNewParameter->SetDocument(pDocTo);
        newParamsMap.insert(make_pair(newParamDefId, opNewParameter->Clone()));
    }

    paramMap.swap(newParamsMap);
}

namespace gcmp
{
    class CopyElementsBatchDataChangeRequest : public IBatchDataChangeRequest
    {
    public:
        CopyElementsBatchDataChangeRequest(
            IDocument* pDocTo, 
            IDocument* pDocFrom, 
            const std::vector<ElementId>& souceElementIds, 
            const std::vector<ElementId>& sourceEleIds, 
            ElementId &modelViewId, 
            const Vector3d& toPoint, 
            const Vector3d& fromPoint,
            std::unordered_map<ElementId, ElementId, ElementIdHash>& newToOldIdTable,
            std::unordered_set<ElementId, ElementIdHash>& copiedElementIds);

    public:
        virtual bool Execute() override;

    private:
        IDocument* m_pDocTo; 
        IDocument* m_pDocFrom; 
        const std::vector<ElementId>& m_souceElementIds; 
        const std::vector<ElementId>& m_sourceEleIds; 
        ElementId& m_modelViewId; 
        const Vector3d& m_toPoint; 
        const Vector3d& m_fromPoint;

    private:
        std::unordered_map<ElementId, ElementId, ElementIdHash>& m_newToOldIdTable;
        std::unordered_set<ElementId, ElementIdHash>& m_copiedElementIds;
    };
}

CopyElementsBatchDataChangeRequest::CopyElementsBatchDataChangeRequest(
    IDocument* pDocTo, 
    IDocument* pDocFrom, 
    const std::vector<ElementId>& souceElementIds, 
    const std::vector<ElementId>& sourceEleIds, 
    ElementId &modelViewId, 
    const Vector3d& toPoint, 
    const Vector3d& fromPoint,
    std::unordered_map<ElementId, ElementId, ElementIdHash>& newToOldIdTable,
    std::unordered_set<ElementId, ElementIdHash>& copiedElementIds):
    m_pDocTo(pDocTo),
    m_pDocFrom(pDocFrom),
    m_souceElementIds(souceElementIds),
    m_sourceEleIds(sourceEleIds),
    m_modelViewId(modelViewId),
    m_toPoint(toPoint),
    m_fromPoint(fromPoint),
    m_newToOldIdTable(newToOldIdTable),
    m_copiedElementIds(copiedElementIds)
{
}

bool CopyElementsBatchDataChangeRequest::Execute()
{
    //输入参数初始化
    IDocument* pDocTo = m_pDocTo; 
    IDocument* pDocFrom = m_pDocFrom; 
    const std::vector<ElementId>& souceElementIds = m_souceElementIds; 
    const std::vector<ElementId>& sourceEleIds = m_sourceEleIds; 
    ElementId& modelViewId = m_modelViewId; 
    const Vector3d& toPoint = m_toPoint; 
    const Vector3d& fromPoint = m_fromPoint;

    //需要被复制的Element的集合
    std::unordered_set<ElementId, ElementIdHash>& copiedElementIds = m_copiedElementIds;
    copiedElementIds.clear();

    //新Element与旧Element的映射
    std::unordered_map<ElementId, ElementId, ElementIdHash>& newToOldIdTable = m_newToOldIdTable;
    newToOldIdTable.clear();

    //源Element与目标Element的映射
    std::map<ElementId, ElementId> sourceToTargetIds;

    //顶层的编辑模式
    const IEditMode* pTopActiveEditMode = IEditMode::GetTopActiveEditMode(pDocTo);
    if (pTopActiveEditMode && pTopActiveEditMode->GetEditModeBehavior())
    {
        const IEditModeCopyPasteComponent* pEditModeCopyPasteComponent
            = dynamic_cast<const IEditModeCopyPasteComponent*>(pTopActiveEditMode->GetEditModeBehavior());
        if (pEditModeCopyPasteComponent)
        {
            // 获取源文档编辑模式下的对象到当前编辑模式下对象的映射关系，当前编辑模式属于目标文档
            pEditModeCopyPasteComponent->GetElementIdMap(pDocFrom, pDocTo, souceElementIds, sourceToTargetIds);
        }
    }

    //被复制的目标Element的集合
    std::set<ElementId> copiedTargetElemIds;

    //同文档复制
    if (pDocFrom == pDocTo)
    {
        const ICopyOperator* pDefaultCopyOperator = ICopyOperator::Get();
        DBG_WARN_UNLESS(pDefaultCopyOperator != nullptr, L"默认的拷贝器不应该为空",L"GDMPLab",L"2024-03-30");
        std::vector<ElementId> copyElementsRes;
        if(DEBUG_MODE(CopyAndChangeModelViewId))
        {
            copyElementsRes = pDefaultCopyOperator->CopyElements(pDocFrom, sourceEleIds, sourceToTargetIds, &copiedTargetElemIds, modelViewId, nullptr, nullptr);
        }
        else
        {
            copyElementsRes = pDefaultCopyOperator->CopyElements(pDocFrom, sourceEleIds, sourceToTargetIds, &copiedTargetElemIds);
        }

        copiedElementIds.clear();
        copiedElementIds.insert(copyElementsRes.begin(), copyElementsRes.end());
    }
    //非文档复制
    else
    {
        // 不支持不同类型文档间的复制
        if (pDocFrom->IsFamilyDocument() != pDocTo->IsFamilyDocument())
        {
            ClipBoard::Get()->SetErrorMessage(GBMP_TR(L"目前仅支持同类型文档间的复制！"));
            return false;
        }

        std::vector<ElementId> copyElementsRes = CopyElementsImpl().CopyElements(pDocFrom, pDocTo, modelViewId, sourceEleIds, newToOldIdTable, sourceToTargetIds);
        copiedElementIds.clear();
        copiedElementIds.insert(copyElementsRes.begin(), copyElementsRes.end());

        copiedTargetElemIds.insert(copiedElementIds.begin(), copiedElementIds.end());
    }

    if (copiedElementIds.empty())
    {
        return false;
    }

    Vector3d offset = toPoint - fromPoint;
    OwnerPtr<ICopyContext> opCopyContext = ICopyContext::Create(copiedElementIds);
    OwnerPtr<IPasteContext> opPasteContext = IPasteContext::Create(TransferOwnership(opCopyContext), pDocFrom, fromPoint, toPoint, newToOldIdTable);

    FOR_EACH(id, copiedElementIds)
    {
        //---------------------------------------------------------------------
        //如果是同文档同楼层的复制粘贴，则不需要关联楼层及偏移的重新计算
        if (pDocFrom == pDocTo && MathUtils::IsZero(offset.Z()))
        {
            continue;
        }

        const IElement* pCopiedElement = pDocTo->GetElement(id);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCopiedElement, L"复制的对象有空值！",L"GDMPLab",L"2024-03-30");
        const IElementCopyPasteComponent * pICopyPasteComponent = pCopiedElement->GetCopyPasteComponent();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pICopyPasteComponent, L"pICopyPasteComponent空值！",L"GDMPLab",L"2024-03-30");
        OwnerPtr<IPasteHelper> oPasteHelper = pICopyPasteComponent->GetPasteHelper();
        if (oPasteHelper)
        {
            oPasteHelper->TranslateAlongZDirection(*opPasteContext);
            continue;
        }

        IElement* pCopiedElementFW = pDocTo->GetElement(id);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCopiedElementFW, L"复制的对象有空值！",L"GDMPLab",L"2024-03-30");
        CopyElementsByPositionBehavior(pCopiedElementFW, pDocFrom, pDocTo, id, newToOldIdTable, offset);
    }

    //更新视图的工作楼层
    FOR_EACH(id, copiedTargetElemIds)
    {
        //如果是同文档同楼层的复制粘贴，则不需要重新计算工作楼层
        if (pDocFrom == pDocTo && MathUtils::IsZero(offset.Z()))
        {
            continue;
        }

        const IElement* pCopiedElement = pDocTo->GetElement(id);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCopiedElement, L"复制的对象有空值！",L"GDMPLab",L"2024-03-30");
        if (const IModelView* pModelView = quick_cast<const IModelView>(pCopiedElement))
        {
            if (nullptr == pModelView->GetDocument() || !GbmpModelViewUtil::GetWorkLevelId(pModelView).IsValid())
            {
                continue;
            }

            //更新后理论工作楼层标高值
            const IDocument* pDocModelView = pModelView->GetDocument();
            ElementId modelViewId = GbmpModelViewUtil::GetWorkLevelId(pModelView);
            const ILevel* pElevation = LevelUtils::GetLevelById(pDocModelView, modelViewId);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pElevation, L"目标文档的粘贴楼层为空！",L"GDMPLab",L"2024-03-30");
            double elevation = pElevation->GetElevation() + offset.Z();

            //更新后的实际工作楼层
            const ILevel* pNewLevel = LevelUtils::GetLowerStoreyLevel(pDocTo, elevation);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(nullptr != pNewLevel, L"pNewLevel为空！",L"GDMPLab",L"2024-03-30");
            double newElevation = pNewLevel->GetElevation();
            ElementId newLevelId = ClipBoardUtils::FindNearestLevelByHeight(pDocTo, newElevation);

            IElement* pCopiedElementFW = pDocTo->GetElement(id);
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pCopiedElementFW, L"复制的对象有空值！",L"GDMPLab",L"2024-03-30");
            IModelView* pModelViewFW = quick_cast<IModelView>(pCopiedElementFW);
            GbmpModelViewUtil::SetWorkLevelId(pModelViewFW, newLevelId);
        }
    }

    return true;
}

//把一堆Element从一个楼层拷贝至另一个楼层（会自动调整拷贝完成后的绑定标高）
//说明：
//(1) 目前这个CopyOperator::CopyElements只能满足同文档的COPY，未来需要重载一个跨文档的COPY函数
//(2）重载COPY函数后，参数pDocFrom应该是const的
static bool CopyElements(
    IDocument* pDocFrom, 
    const std::vector<ElementId>& sourceEleIds, 
    IDocument* pDocTo, 
    ElementId modelViewId, 
    const Vector3d& fromPoint, 
    const Vector3d& toPoint, 
    std::vector<ElementId>& pastedIds, 
    bool isEditMode, 
    std::wstring editModeType, 
    const std::vector<ElementId>& souceElementIds)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDocFrom && pDocTo, L"复制传入的文档参数不正确！",L"GDMPLab",L"2024-03-30");

    //因为单文档复制和跨文档复制函数CopyOperator::CopyElements逻辑有些不同，错误判断标准也不同
    //所以这里提前做一次业务上的合法性检测(错误信息存储在剪切板对象中，未来会统一剪切板错误报告流程)
    if(!ValidateCopyElements(pDocFrom, sourceEleIds, isEditMode, editModeType, pDocTo))
    {
        //复制内容不合法，复制不成功
        return false;
    }

    //需要被复制的Element的集合
    std::unordered_set<ElementId, ElementIdHash> copiedElementIds;
    //新Element与旧Element的映射
    std::unordered_map<ElementId, ElementId, ElementIdHash> newToOldIdTable;

    //复制到调整标高结束，这一整个过程中都不要对目标文档做关联更新(因为关联关系处于逐步建立中)
    //在调整结束后，所有对象及其属性都处于正确状态，再集中进行关联更新 :)
    IRegenerator * pIRegenerator = pDocTo->GetRegenerator();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pIRegenerator, L"目标文档的pIRegenerator为空？！",L"GDMPLab",L"2024-03-30");
    pIRegenerator->BatchDataChange(
        &CopyElementsBatchDataChangeRequest(
            pDocTo, 
            pDocFrom, 
            souceElementIds, 
            sourceEleIds, 
            modelViewId, 
            toPoint, 
            fromPoint, 
            newToOldIdTable,
            copiedElementIds));

    //---------------------------------------------------------------------
    //调整对象的位置到目标位置(必须等上面的标高调整好后进行)
    Vector3d offset = toPoint - fromPoint;
    OwnerPtr<ICopyContext> opCopyContext = ICopyContext::Create(copiedElementIds);
    OwnerPtr<IPasteContext> opPasteContext = IPasteContext::Create(TransferOwnership(opCopyContext), pDocFrom, fromPoint, toPoint, newToOldIdTable);
    OwnerPtr<IElementMoveContext> opMoveContext = IElementMoveContext::CreateElementMoveContext(pDocTo, copiedElementIds, offset);

    FOR_EACH(id, copiedElementIds)
    {
        const IElement* pCopiedElement = pDocTo->GetElement(id);
        if (nullptr == pCopiedElement)//因为有些对象被临时过滤了
        {
            continue;
        }
        const IElementCopyPasteComponent * pICopyPasteComponent = pCopiedElement->GetCopyPasteComponent();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pICopyPasteComponent, L"拷贝组件为空？",L"GDMPLab",L"2024-03-30");

        OwnerPtr<IPasteHelper> oPasteHelper = pICopyPasteComponent->GetPasteHelper();
        if (oPasteHelper)
        {
            oPasteHelper->TranslateInXYPlane(*opPasteContext);
            continue;
        }


        //首先判断当前元素是否是随Host对象一起复制，如果不是才可以进行独立偏移
        bool needTranslation = true;
        if(const IInstance* pInstance = quick_cast<const IInstance>(pCopiedElement))
        {
            ElementId hostId = pInstance->GetHostInstanceId();
            if(hostId.IsValid() && copiedElementIds.find(hostId) != copiedElementIds.end())
            {
                //有Host对象一起被复制，它不需要作独立偏移
                needTranslation = false;
            }
        }

        Vector3d translation(offset);
        if(needTranslation)
        {
            const IElementPosition* posBehavior = pCopiedElement->GetElementPosition();
            //梁柱是可以改变Z值得，这里要忽略Z值，否则会二次偏移
            if(posBehavior)
            {
                translation.SetZ(0.0);
            }
            opMoveContext->SetMoveVector(translation);

            IElement* pCopiedElementFW = pDocTo->GetElement(id);
            if (nullptr == pCopiedElementFW)
            {
                continue;
            }

            //跨文档必须调整好标高绑定再做偏移（否则计算器中标高的id是非法的）
            IElementTransformationComponent *pElementTransformationComponent = pCopiedElementFW->GetElementTransformationComponent();
            if (!pElementTransformationComponent)
            {
                continue;
            }
            pElementTransformationComponent->Translate(*opMoveContext);
        }
    }

    std::copy(copiedElementIds.begin(), copiedElementIds.end(), std::back_inserter(pastedIds));

    return true;
}

ClipBoard::ClipBoard()
    :m_pDocFrom(nullptr)
    ,m_levelIdFrom(ElementId::InvalidID)
    ,m_elementIds()
    ,m_minPt(0.0,0.0,0.0)
    ,m_localCoor(Coordinate3d())
    ,m_insertPt()
    ,m_lastErrorMessage()
    ,m_pastedModelViewId()
    ,m_isEditMode(false)
{
    if (IDocumentManager::Get()->GetDocumentEvent())
    {
        IDocumentManager::Get()->GetDocumentEvent()->Add(this);
    }

    m_opElementChangeHanlder = NEW_AS_OWNER_PTR(ClipBoardElementChangeHandler, this);
}

ClipBoard::~ClipBoard()
{
    if (IDocumentManager::Get()->GetDocumentEvent())
    {
        IDocumentManager::Get()->GetDocumentEvent()->Delete(this);
    }
}

ClipBoard* ClipBoard::Get()
{
    static ClipBoard s_ClipBoard;
    return &s_ClipBoard;
}

void ClipBoard::On(IDocumentEventArgs* pArgs)
{
    if (!pArgs || pArgs->GetType() != DocumentEventType::Closed)
    {
        return;
    }

    //TODO:
    //在刷新UI的机制中，ACTION也需要更新状态。有以下案例：
    //(1)从文档1复制一个构件
    //(2)打开文档2，点击【粘贴】，同时关闭文档1
    //(3)【粘贴】按键失效，但是文档2中的鼠标还处于粘贴状态
    IDocument *pDoc = pArgs->GetDocument();
    if (pDoc == m_pDocFrom)
    {
        ClearContent();
    }

    // 文档关闭时，删除文档中的增删改观察者，有则删之
    if (pDoc != nullptr)
    {
        pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsPreDeletionEvent, m_opElementChangeHanlder.get());
    }
}

bool ClipBoard::Copy(IDocument* pDocFrom, const ElementId& viewIdFrom, const std::vector<ElementId>& elemIds)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDocFrom != nullptr, L"复制来源文档不能为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(!elemIds.empty(), L"复制来源内容不能为空！",L"GDMPLab",L"2024-03-30");

    const IElement* pElement = pDocFrom->GetElement(viewIdFrom);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"pElement不能为空",L"GDMPLab",L"2024-03-30");
    const IModelView* pView = quick_cast<IModelView>(pElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pView, L"pView不能为空",L"GDMPLab",L"2024-03-30");

    std::vector<ElementId> elemIdsInputted;
    elemIdsInputted.reserve(elemIds.size());
    //检测复制合法性
    FOR_EACH(id, elemIds)
    {
        const IElement* curEle = pDocFrom->GetElement(id);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(curEle, L"复制对象不能为空！",L"GDMPLab",L"2024-03-30");
        const IElementCopyPasteComponent * pICopyPasteComponent = curEle->GetCopyPasteComponent();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pICopyPasteComponent, L"pICopyPasteComponent为空",L"GDMPLab",L"2024-03-30");
        std::wstring cannotCopiedExplanation = L"";
        if(!pICopyPasteComponent->CanBeCopied(&cannotCopiedExplanation))
        {
            // subInstance不支持copy，当和其他superInstance一起被选中时，期望也能copy
            const IInstance* pInstance = quick_cast<IInstance>(curEle);
            if (pInstance && pInstance->GetSuperInstanceId().IsValid())
                continue;

            //复制不成功：
            //后续可以向调用层提供不成功的描述信息
            return false;
        }
        elemIdsInputted.emplace_back(id);
    }

    Box3d box = RegenBoundingBox(pDocFrom, viewIdFrom, elemIdsInputted);
    if(box.IsEmpty())
    {
        m_elementIds.clear();
        return true;
    }

    m_sourceOrgin = box.GetMinPoint();

    //复制成功
    m_pDocFrom = pDocFrom;
    m_levelIdFrom = GbmpModelViewUtil::GetWorkLevelId(pView);
    m_elementIds = elemIdsInputted;
    FOR_EACH(elemId, elemIdsInputted)
    {
        m_elementIdsSet.insert(elemId);
    }

    const IEditMode* pTopActiveEditMode = IEditMode::GetTopActiveEditMode(pDocFrom);
    const IEditModeCopyPasteComponent* pEditModeCopyPasteComponent = nullptr;
    if (pTopActiveEditMode && pTopActiveEditMode->GetEditModeBehavior())
    {
        pEditModeCopyPasteComponent = dynamic_cast<const IEditModeCopyPasteComponent*>(pTopActiveEditMode->GetEditModeBehavior());
    }

    if (pEditModeCopyPasteComponent)
    {
        m_isEditMode = true;
        m_sourceElementIds.clear();
        m_editModeType = pEditModeCopyPasteComponent->GetEditModeInfo(pTopActiveEditMode->GetDocument(), m_sourceElementIds);
    }
    else
    {
        m_isEditMode = false;
        m_editModeType = L"";
        m_sourceElementIds.clear();
    }

    // 拷贝成功，那就注册一个handler观察源文档的element的增删改情况？
    if (m_pDocFrom != nullptr)
    {
        m_pDocFrom->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsPreDeletionEvent, m_opElementChangeHanlder.get());
    }

    return true;
}

bool ClipBoard::Paste(IDocument* pDocTo, const ElementId& modelViewId, const Vector3d& pt, std::vector<ElementId>& pastedIds)
{
    DBG_WARN_AND_RETURN_UNLESS(pDocTo != nullptr, false, L"粘贴的目标文档为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(HasContent(), false, L"粘贴的内容为空",L"GDMPLab",L"2024-03-30");

    const std::vector<ElementId>& levelIdsTo = m_levelIdsTo;

    //来源标高
    ILevel* pLevelFrom = LevelUtils::GetLevelById(m_pDocFrom, m_levelIdFrom);
    DBG_WARN_AND_RETURN_UNLESS(!m_editModeType.empty() || pLevelFrom, false, L"无法获得粘贴操作的来源标高！",L"GDMPLab",L"2024-03-30");

    const IEditMode* pTopActiveEditMode = IEditMode::GetTopActiveEditMode(pDocTo);
    const IEditModeCopyPasteComponent* pEditModeCopyPasteComponent = nullptr;
    if (pTopActiveEditMode && pTopActiveEditMode->GetEditModeBehavior())
    {
        pEditModeCopyPasteComponent = dynamic_cast<const IEditModeCopyPasteComponent*>(pTopActiveEditMode->GetEditModeBehavior());
    }

    bool isSketchEMT = pTopActiveEditMode && pEditModeCopyPasteComponent;
    //粘贴操作
    FOR_EACH(levelId, levelIdsTo)
    {
        ILevel* pLevelTo = LevelUtils::GetLevelById(pDocTo, levelId);
        DBG_WARN_AND_RETURN_UNLESS(isSketchEMT || pLevelTo, false, L"目标文档的粘贴楼层为空！",L"GDMPLab",L"2024-03-30");

        //-----------------------------------------------------------------------------
        //计算复制对象的目标位置偏移（相对于复制来源时刻的坐标）
        double h0 = 0;
        double h1 = 0;
        if(!isSketchEMT)
        {
            h0 = pLevelFrom->GetElevation();
            h1 = pLevelTo->GetElevation();
        }

        Vector3d fromPoint(m_minPt.X(), m_minPt.Y(), h0);
        Vector3d toPoint(pt.X(), pt.Y(), h1);
        //-----------------------------------------------------------------------------
        //执行真正的复制粘贴(将一堆对象从一个参考楼层复制至另一个参考楼层，并且有水平方向偏移)
        bool ret = CopyElements(
            m_pDocFrom, 
            m_elementIds, 
            pDocTo, 
            modelViewId, 
            fromPoint, 
            toPoint, 
            pastedIds, 
            m_isEditMode, 
            m_editModeType, 
            m_sourceElementIds);

        if (!ret)
        {
            //粘贴过程中发生异常(一般是业务上粘贴行为不合理)
            return false;
        }
    }

    //标高调整好了，更新一下"所有"被copyed的Elements
    IRegenerator * pIRegenerator = pDocTo->GetRegenerator();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pIRegenerator, L"目标文档的pIRegenerator为空？！",L"GDMPLab",L"2024-03-30");
    FOR_EACH(pastedId, pastedIds)
    {
        pIRegenerator->RegenerateElement(pastedId);
    }

    //更新粘贴目标的包围盒(复制时并不能计算出真正的包围盒，这个包围盒必需是目标文档的)
    m_localCoor = Coordinate3d();
    Box3d box3d;
    if(isSketchEMT)
    {
        m_localCoor = pEditModeCopyPasteComponent->GetCoordinate(pTopActiveEditMode->GetDocument());
        box3d = RegenBoundingBoxForSketch(pDocTo, m_pastedModelViewId, m_localCoor, pastedIds);
    }
    else
    {
        box3d = RegenBoundingBox(pDocTo, m_pastedModelViewId, pastedIds);
    }
    
    if(box3d.IsEmpty())
    {
        box3d.Set(m_sourceOrgin, m_sourceOrgin);
    }

    CaculateCorners(box3d, m_corners);
    
    //更新包围盒相关信息
    m_minPt = m_localCoor.GetWorldPoint(m_corners[0]);

    //更新插入点
    m_insertPt=m_minPt;

    return true;
}

void ClipBoard::ClearContent()
{
    m_pDocFrom = nullptr;
    m_levelIdFrom = ElementId::InvalidID;
    m_elementIds.clear();
    m_elementIdsSet.clear();
    m_minPt = Vector3d(0.0, 0.0, 0.0);
}

bool ClipBoard::PasteElevationView(IDocument* pDocTo, ElementId modelViewId, const Vector3d& pt, std::vector<ElementId>& pastedIds)
{
    DBG_WARN_AND_RETURN_UNLESS(pDocTo != nullptr, false, L"粘贴的目标文档为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(HasContent(), false, L"粘贴的内容为空",L"GDMPLab",L"2024-03-30");

    // -----------------------------------------------------------------------------
    // 执行真正的复制粘贴(将一堆对象从一个参考楼层复制至另一个参考楼层，并且有水平方向偏移)
    bool ret = CopyElements(
        m_pDocFrom, 
        m_elementIds, 
        pDocTo, 
        modelViewId, 
        m_minPt, 
        pt, 
        pastedIds, 
        m_isEditMode, 
        m_editModeType, 
        m_sourceElementIds);

    if (!ret)
    {
        // 粘贴过程中发生异常(一般是业务上粘贴行为不合理)
        return false;
    }

    return true;
}

// 更新包围盒及相关数据
Box3d ClipBoard::RegenBoundingBox(const IDocument* pDoc, ElementId viewId, const std::vector<ElementId>& pastedIds) const
{
    Box3d box3d;
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, box3d, L"文档为空",L"GDMPLab",L"2024-03-30");

    //计算缓存包围盒相关的数据
    FOR_EACH(id, pastedIds)
    {
        const IElement* curElement = pDoc->GetElement(id);
        if (curElement)
        {
            const IElementCopyPasteComponent* pICopyPasteComponent = curElement->GetCopyPasteComponent();
            GBMP_ASSERT(pICopyPasteComponent != nullptr);
            const IElementStatus* pStatus = curElement->GetStatus();
            DBG_WARN_AND_RETURN_UNLESS(pStatus, box3d, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
            if (!pStatus->IsVisible())
            {
                continue;
            }
        }

        IElement* pElement = pDoc->GetElement(viewId);
        DBG_WARN_AND_RETURN_UNLESS(pElement, box3d, L"pElement不能为空",L"GDMPLab",L"2024-03-30");
        const IModelView* pModelView = quick_cast<const IModelView>(pElement);
        DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, box3d, L"视图为空",L"GDMPLab",L"2024-03-30");

        //调用element的CreateGrepInView接口,获得用户在制定modelview里创建的grep
        OwnerPtr<IGraphicsElementShape> pGrepInView = pModelView->CreateModelViewElementShape(curElement);

        if (pGrepInView)
        {
            pGrepInView->SetBox(GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, pGrepInView.get()));
            box3d.MergeBox(pGrepInView->GetBox());
        }
        else
        {
            DBG_WARN_AND_RETURN_UNLESS(curElement, box3d, L"curElement为空",L"GDMPLab",L"2024-03-30");
            DBG_WARN_AND_RETURN_UNLESS(curElement->GetElementModelShape(), box3d, L"curElement为空",L"GDMPLab",L"2024-03-30");
            if (const IGraphicsElementShape* pGRep = curElement->GetElementModelShape()->GetGraphicsElementShape())
            {
                box3d.MergeBox(pGRep->GetBox());
            }
        }
    }

    return box3d;
}

Box3d ClipBoard::RegenBoundingBoxForSketch(const IDocument* pDoc, ElementId viewId, const Coordinate3d& coor, const std::vector<ElementId>& pastedIds) const
{
    Box3d box3d;
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, box3d, L"文档为空",L"GDMPLab",L"2024-03-30");

    // 计算缓存包围盒相关的数据
    Matrix4d matrix;
    coor.GetLocalMatrix(matrix);
    FOR_EACH(id, pastedIds)
    {
        const IElement* curEle = pDoc->GetElement(id);
        DBG_WARN_AND_RETURN_UNLESS(curEle, box3d, L"curEle为空",L"GDMPLab",L"2024-03-30");
        const IElementStatus* pStatus = curEle->GetStatus();
        DBG_WARN_AND_RETURN_UNLESS(pStatus, box3d,L"无法获取状态集",L"GDMPLab",L"2024-03-30");
        if (!pStatus->IsVisible())
            continue;

        IElement* pElement = pDoc->GetElement(viewId);
        DBG_WARN_AND_RETURN_UNLESS(pElement, Box3d(), L"pElement不能为空",L"GDMPLab",L"2024-03-30");
        const IModelView* pModelView = quick_cast<const IModelView>(pElement);
        DBG_WARN_AND_RETURN_UNLESS(pModelView != nullptr, Box3d(), L"视图为空",L"GDMPLab",L"2024-03-30");

        // 调用element的CreateGrepInView接口,获得用户在制定modelview里创建的grep
        OwnerPtr<IGraphicsElementShape> pGrepInView = pModelView->CreateModelViewElementShape(curEle);
        OwnerPtr<IGraphicsElementShape> pGrepTemp = nullptr;
        if (pGrepInView)
        {
            pGrepTemp = TransferOwnershipCast<IGraphicsElementShape>(pGrepInView->Clone());
        }
        else if(const IGraphicsElementShape* pGrep = curEle->GetElementModelShape()->GetGraphicsElementShape())
        {
            pGrepTemp = TransferOwnershipCast<IGraphicsElementShape>(pGrep->Clone());
        }

        if(pGrepTemp)
        {
            pGrepTemp->Transform(matrix);
            std::vector<OwnerPtr<IGraphicsNode>>& gNodes = pGrepTemp->GetChildrenFw();
            FOR_EACH(gNode, gNodes)
            {
                IGraphicsZoomFree* pGZoomFree = quick_cast<IGraphicsZoomFree>(gNode.get());
                if(pGZoomFree)
                {
                    Coordinate3d coor = pGZoomFree->GetCoordinate();
                    coor.Transform(matrix);
                    pGZoomFree->SetCoordinate(coor);
                }
            }

            pGrepTemp->SetBox(GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, pGrepInView.get()));
            box3d.MergeBox(pGrepTemp->GetBox());
        }
    }
    return box3d;
}

void ClipBoard::CaculateCorners(const Box3d& box3d, std::vector<Vector3d>& corners)
{
    Vector3d minPoint = box3d.GetMinPoint();
    Vector3d maxPoint = box3d.GetMaxPoint();
    Vector3d lb = minPoint;
    Vector3d lt = Vector3d::Create(minPoint.X(), maxPoint.Y(), minPoint.Z());
    Vector3d rb = Vector3d::Create(maxPoint.X(), minPoint.Y(), minPoint.Z());
    Vector3d rt = Vector3d::Create(maxPoint.X(), maxPoint.Y(), minPoint.Z());

    corners.clear();
    corners.push_back(lb);
    corners.push_back(lt);
    corners.push_back(rb);
    corners.push_back(rt);
}
